package main

import (
	"fmt"
	"reflect"
)

func main() {
	// fmt.Println("传入nil")
	// Switch(nil)
	// fmt.Println("传入*user(nil)")
	// Switch((*User)(nil))
	ReflectValueAndElem()
}

func Switch(val any) {
	// 接口与nil比较——变量的比较
	// (*User)(nil) 相当于把核心的*user的指针指向了nil，然后函数参数自动将值为nil的User变量地址
	// “装箱”为interface的结构：
	// type eface struct {
	// 	_type *_type
	// 	data  unsafe.Pointer
	// }
	// type iface struct {
	// 	tab  *itab
	// 	data unsafe.Pointer
	// }
	// 而interface结构与nil变量的比较，已经不是空interface{}，所以与nil不相等。
	// 当空接口被赋值之后，data的指针就变了，而赋值的两个都是一样的类型，
	// 所以，动态类型的部分，指针是一样的
	fmt.Println("any与nil比较:", val == nil) // false

	switch v := val.(type) {
	// 类型断言走的是interface的逻辑，v也是一个interface,只是val是一个空接口,而v是一个实际的接口
	case nil:
		// 并非表示nil是一个类型，而是说val变量内存标识是不是等于nil这个变量
		fmt.Println("val is nil")
	case int:
		println(v)                              //0
		fmt.Println(reflect.TypeOf(v).String()) // int

	case *User:
		println(val) // (0x83f3c0,0x0)
		println(v)   // (0x0) 取出了any结构中指向值的部分
		var g = &User{Name: "hahah"}
		println(g) // 0xc000115ea8
		var i interface{} = g
		println(i)                                   // (0x83f3c0,0xc000115ea8)
		fmt.Println(reflect.TypeOf(v).String())      // *main.User
		fmt.Println(reflect.TypeOf(val).String())    // *main.User
		fmt.Println(reflect.TypeOf(v).Elem().Kind()) // struct
		// 可以看到经过类型断言,val interface类型已经取出值的部分并赋值给了v
		fmt.Println("val is User")
		fmt.Println(val == nil) // false 因为类型本身不相等，所以比较也不相等的,本质上是空interface{}与nil比较——类型不对应
		fmt.Println(nil == v)   // true，本质上是实际变量与nil变量的比较,都为0值则表示相等，v为指向User结构的指针，只针对的值为零值，所以与nil相等
		fmt.Println(val == v)   // true, 空interface结构与实际interface的比较.先比较类型再比较值
		// 类型相等的情况下,data也相等,所以相等.本质上是接口与实际值的比较.
		if v == nil {
			fmt.Println("val is User , but is nil too")
		}
	default:
		fmt.Println("invalid !")
	}
}

type User struct {
	Name string
	Age  int
}
